﻿//Copyright © 2012  Daniel Lopez

//This program is free software; you can redistribute it and/or
//modify it under the terms of the GNU General Public License
//as published by the Free Software Foundation; either version 2
//of the License, or (at your option) any later version.

//This program is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//GNU General Public License for more details.

//You should have received a copy of the GNU General Public License
//along with this program; if not, write to the Free Software
//Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Xml.Serialization;
using System.Diagnostics;
namespace NASM_Develop_IDE
{
    public partial class MainWindow : Form
    {
        private Solution currentSolution;
        private delegate void InvokeDelegate(string o);
        public MainWindow(string[] args = null)
        {
            InitializeComponent();
            ActiveControl =  nasmTabList;
            currentSolution = null;
            TextBoxHighlighter.Highlight(searchMenuItems.TextBox, "Convenient Menu Search");
            if (args != null)
            {
                ProcessArgs(args);
            }
            
        }


      

        

        void item_Click(object sender, EventArgs e)
        {
            outputWindow.Clear();
        }
        private void ProcessArgs(string[] args)
        {
            foreach (string arg in args)
            {
                try
                {
                    FileInfo file = new FileInfo(arg);
                    if (file.Exists)
                    {
                        if (file.Extension.Contains("nasmproj"))
                        {
                            Solution currentSolution = null;
                            currentSolution = Solution.GetSolution(file.FullName);
                            if (currentSolution != null)
                            {
                                this.currentSolution = currentSolution;
                                List<string> sourcePaths = currentSolution.AbsolutePathOfSources;
                                sourcePaths.ForEach(delegate(string path)
                                {

                                    nasmTabList.AddTab(path);

                                });
                                nasmTabList.Solution = this.currentSolution;
                            }
                            else
                            {
                                ExceptionPrinter.Print(new NullReferenceException("Error Solution Object Is Not Referencing A Valid Object!"));
                                MessageBox.Show("Application Crashed! Please Read The Handy Log File For Assistance (It Is In The Directory Of This Application). If the Log File Is Not Found Then Please Call Your Local Emergency Center.", "Oh Dear Something Wen't Wrong!", MessageBoxButtons.OK, MessageBoxIcon.Error);
                                this.Close();

                            }
                            break;
                        }
                    }
                }
                catch
                {
                    break;
                }
                
               
            }
        }
        private void newToolStripMenuItem_Click(object sender, EventArgs e)
        {
            using (NewProjectDialog dialog = new NewProjectDialog())
            {
                DialogResult result = dialog.ShowDialog();
                if (result == System.Windows.Forms.DialogResult.OK && dialog.SuccessfullyClosedWithOKAY)
                {
                     this.currentSolution = dialog.ProjectSolution;
                     if (currentSolution != null)
                     {
                        List<string> sourcePaths =  currentSolution.AbsolutePathOfSources;
                        sourcePaths.ForEach(delegate(string path)
                        {
                            using (FileStream stream = File.Create(path))
                            {
                                GC.Collect();
                                string sourceName = Path.GetFileName(path);
                                if (dialog.Author == null)
                                {
                                    using (StreamWriter writer = new StreamWriter(stream))
                                    {
                                        writer.Write("; Author: " + "Unknown" + "\n;Created On: " + DateTime.Now.ToString());
                                    }
                                    nasmTabList.AddTab(path);
                                }
                                else
                                {
                                    using (StreamWriter writer = new StreamWriter(stream))
                                    {
                                        writer.Write("; Author: " + dialog.Author + "\n;Created On: " + DateTime.Now.ToString());
                                    }
                                    nasmTabList.AddTab(path);
                                }
                            }
                        });
                        nasmTabList.Solution = this.currentSolution;
                     }
                     else
                     {
                         ExceptionPrinter.Print(new NullReferenceException("Error Solution Object Is Not Referencing A Valid Object!"));
                         MessageBox.Show("Application Crashed! Please Read The Handy Log File For Assistance (It Is In The Directory Of This Application). If the Log File Is Not Found Then Please Call Your Local Emergency Center.", "Oh Dear Something Wen't Wrong!", MessageBoxButtons.OK, MessageBoxIcon.Error);
                         this.Close();

                     }
                }
            }

        }

        private void configuringEnviornmentToolStripMenuItem_Click(object sender, EventArgs e)
        {
            MessageBox.Show("Configuring the environment is easy as differential equations (Okay maybe not the best example).\n\n•Step 1:\n - Download MinGW and NASM:\nVersion might not matter But try The latest stable version, and never use the beta or unstable versions unless you are sure you want to.\n•Step 2:\n Then unzip the folder of both the NASM enviroment and MinGW (It is recommended to leave it in the default root folder of your default drive (typically the C drive).\n•Step 3:\nSetup the environment variables. Let's say in this case that the NASM enviornment is located in C:\\<Name Of NASM Environment Folder> (For MinGW it would be the bin folder but for NASM the root folder of the environment will do). Then the that is the value the environment variable will contain in the %PATH% variable. That is basically it, test that everything has been setup, by running your favorite command line shell like PowerShell (don't let the power part scare you it is just a shell), Bash (wait this isn't Linux), Terminal (wait this isn't Mac OSX too), or Command Prompt. Then type gcc then nasm and see if it finds the command. If it doesn't then you have broken your computer and you must take it to the repair shop...no--wait I was kidding, but you definetly setup the enviornment wrong. Or you forgot to restart the shell if you already had it running.\n\nFAQS:\nQ: May I use Cygwin? A: Maybe but try at your own risk since the IDE is probably not going to communicate with Cygwin since this IDE was designed for writing native Windows applications. But rest assure this IDE might be ported to other OSes like Linux and maybe MAC OS X (if I every use one which I would like to but cash doesn't grow on trees but ironically it is made up of paper.)", "How To Setup Environment!", MessageBoxButtons.OK, MessageBoxIcon.Information);
        }

        private void aboutNASMDevelopIDEToolStripMenuItem_Click(object sender, EventArgs e)
        {
            using (AboutDialog dlg = new AboutDialog())
            {
                dlg.ShowDialog();
            }
        }

        private void MainWindow_FormClosed(object sender, FormClosedEventArgs e)
        {
            
        }
        ~MainWindow()
        {
            currentSolution = null;
            GC.Collect();
        }

        private void openToolStripMenuItem_Click(object sender, EventArgs e)
        {
            using (OpenFileDialog open = new OpenFileDialog())
            {
                open.Filter = "NASM Develop IDE Projects|*.nasmproj";
                DialogResult result = open.ShowDialog();
                if (result == System.Windows.Forms.DialogResult.OK)
                {
                    Solution currentSolution = null;
                    currentSolution = Solution.GetSolution(open.FileName);
                    if (currentSolution != null)
                    {
                        if (this.currentSolution != currentSolution)
                        {
                            this.currentSolution = currentSolution;
                            List<string> sourcePaths = currentSolution.AbsolutePathOfSources;
                            sourcePaths.ForEach(delegate(string path)
                            {

                                nasmTabList.AddTab(path);

                            });
                            nasmTabList.Solution = this.currentSolution;
                        }
                        else
                        {
                            MessageBox.Show("Trying To Open A Project That Is Already Opened! Not Sensing The Reason On That!", "Why!!!!!", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                        }
                    }
                    else
                    {
                        ExceptionPrinter.Print(new NullReferenceException("Error Solution Object Is Not Referencing A Valid Object!"));
                        MessageBox.Show("Application Crashed! Please Read The Handy Log File For Assistance (It Is In The Directory Of This Application). If the Log File Is Not Found Then Please Call Your Local Emergency Center.", "Oh Dear Something Wen't Wrong!", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        this.Close();

                    }
                }
            }
        }

        private void menuStrip1_KeyUp(object sender, KeyEventArgs e)
        {
            
        }

        private void searMenuItems_KeyUp(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Enter)
            {
                string command = searchMenuItems.Text;
                switch (command)
                {
                    case "File->New":
                    {
                        newToolStripMenuItem_Click(this, new EventArgs()); // Simulate The Click By Literally Calling The Callback method used By The Instance Delegate (Event) 
                        break;
                    }
                    case "File->Open":
                    {
                        openToolStripMenuItem_Click(this, new EventArgs());
                        break;
                    }
                    case "File->Save All":
                    {
                        saveAllToolStripMenuItem_Click(this, new EventArgs());
                        break;
                    }
                    case "Build->Compile Without Cleaning":
                    {
                        if (currentSolution != null)
                        compileToolStripMenuItem1_Click(this, new EventArgs());
                        else
                            MessageBox.Show("No Project Is Available! Open Or Create One!", "What The!", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                        break;
                    }
                    case "Build->Clean And Compile":
                    {
                        if (currentSolution != null)
                            cleanAndCompileToolStripMenuItem_Click(this, new EventArgs());
                        else
                            MessageBox.Show("No Project Is Available! Open Or Create One!", "What The!", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                        break;
                    }
                    case "Help->About NASM Develop IDE":
                    {
                        aboutNASMDevelopIDEToolStripMenuItem_Click(this, new EventArgs());
                        break;
                    }
                    case "Help->Configuring Environment":
                    {
                        configuringEnviornmentToolStripMenuItem_Click(this, new EventArgs());
                        break;
                    }
                    case "Help->Fix Broken Project Tool":
                    {
                        fixBrokenProjectToolToolStripMenuItem_Click(this, new EventArgs());
                        break;
                    }
                    case "Build->Link With GCC":
                    {
                        if (currentSolution != null)
                            linkWithMiToolStripMenuItem_Click(this, new EventArgs());
                        else
                            MessageBox.Show("No Project Is Available! Open Or Create One!", "What The!", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                        break;
                    }
                    default:
                    {
                        MessageBox.Show("Menu Item Not Found! If This Troubles You There Is Always The Old Fashion Way--Moving The Pointer And Clicking On The Menu Item Of Choice." + "\n\nTechincal Information Below:\n" + "The Monkeys Internally Working Inside The Computer Couldn't Process The Requested Information.", "",  MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                        break;
                    }
                }
            }
        }

        private void saveAllToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (currentSolution == null)
            {
                MessageBox.Show("Cannot Save If There Is Nothing To Save! To Fix This Problem, Create A New Project Or Open An Existing Project And Then Save.", "Message From Application", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            else
            {
                bool successful  = currentSolution.Save(nasmTabList);
                if (!successful)
                {
                    MessageBox.Show("The Monkeys Internally Working Inside The Computer Failed To Save Everything. There Must Be Problem In The Printing Room But Rest Assure That The Techincal Information Has Been Placed In The Log File Located In The Directory Of This Application. If It Cannot Be Found Please Cry For Help.", "Error In Saving!", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
            }
        }

        private void compileToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            try
            {
                if (currentSolution == null)
                {
                    MessageBox.Show("Cannot Build A Project That Doesn't Exist! Please Create Open Or Open An Existing Project!", "What The!",  MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                }
                else
                {
                    saveAllToolStripMenuItem_Click(this, new EventArgs());
                    using (BuildDialog dlg = new BuildDialog(currentSolution))
                    {
                        DialogResult result = dlg.ShowDialog();
                        if (result == System.Windows.Forms.DialogResult.OK)
                        {
                            nasmTabList.ClearAllError();
                            outputWindow.Clear();
                            outputWindow.Text = dlg.CompilationOutput + "\nCompilation Complete At " + DateTime.Now.ToString();
                            if (!stringIsBlank(dlg.CompilationOutput))
                            {
                                ErrorLineNumbersExtracter extractor = new ErrorLineNumbersExtracter(dlg.CompilationOutput);
                                Dictionary<int, string> lineNumbers = extractor.GetLineNumbers();
                                DictionaryHelper.Foreach<int, string>(lineNumbers, delegate(int lineNumber, string sourceName)
                                {
                                    nasmTabList.SetErrorAt(sourceName, lineNumber);
                                });

                            }
                            else
                            {
                                if (dlg.LinkAfterCompilation)
                                {
                                    using (LinkerDialog lDlg = new LinkerDialog(currentSolution))
                                    {
                                        result = lDlg.ShowDialog();
                                        if (result == System.Windows.Forms.DialogResult.OK)
                                        {
                                            currentSolution.NameOfOutputBinary = lDlg.OutputName;
                                            saveAllToolStripMenuItem_Click(this, new EventArgs());
                                            outputWindow.AppendText("\n" + lDlg.LinkerOutput + "\n" + " Linking Completed On " + DateTime.Now.ToString());
                                            if (lDlg.LinkerOutput != "No Linker Output! Please check if a problem occured In The 'bin' Folder!" || !stringIsBlank(lDlg.LinkerOutput))
                                            {
                                                using (RunDialog rDlg = new RunDialog(currentSolution))
                                                {
                                                    result = rDlg.ShowDialog();
                                                    if (result == System.Windows.Forms.DialogResult.Cancel)
                                                    {
                                                        outputWindow.AppendText("\nUser Canceled Run...\n");
                                                    }

                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                        
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show("Something Went Clearly Wrong, The Application Will Close! The Monkeys Working Internally Did Leave Some Helpful Information In The Current Working Directory Of The Application; If It Cannot Be Found Please Contact Your Local Emergency Center!", "Error Monkeys Tried To Help But Couldn't Solve The Problem", MessageBoxButtons.OK, MessageBoxIcon.Error);
                ExceptionPrinter.Print(ex);
                this.Close();
            }
        }

        private void MainWindow_KeyUp(object sender, KeyEventArgs e)
        {

        }
        private bool stringIsBlank(string str)
        {
            str = str.Replace("\r", "").Replace("\n", "");
            if (str == string.Empty)
            {
                return true;
            }
            List<char> characters = str.ToList();
            List<char> matches = characters.FindAll((char c) => (!char.IsWhiteSpace(c)));
            if (matches == null || matches.Count > 0)
            {
                return false;
            }
            else
            {
                return true;
            }
        }

        private void cleanAndCompileToolStripMenuItem_Click(object sender, EventArgs e)
        {
            try
            {
                if (currentSolution == null)
                {
                    MessageBox.Show("Cannot Build A Project That Doesn't Exist! Please Create Open Or Open An Existing Project!");
                }
                else
                {
                    saveAllToolStripMenuItem_Click(this, new EventArgs());
                    bool cleanSuccessfull = NASMBuilder.Clean(currentSolution.AbsolutePathOfBinFolder);
                    if (!cleanSuccessfull) outputWindow.AppendText("Failed To Clean But Continuing With Build Process!");
                    using (BuildDialog dlg = new BuildDialog(currentSolution))
                    {
                        DialogResult result = dlg.ShowDialog();
                        if (result == System.Windows.Forms.DialogResult.OK)
                        {
                            nasmTabList.ClearAllError();
                            outputWindow.Clear();
                            outputWindow.Text = dlg.CompilationOutput + "\nCompilation Complete At " + DateTime.Now.ToString();
                             if (!stringIsBlank(dlg.CompilationOutput))
                            {
                                ErrorLineNumbersExtracter extractor = new ErrorLineNumbersExtracter(dlg.CompilationOutput);
                                Dictionary<int, string> lineNumbers = extractor.GetLineNumbers();
                                DictionaryHelper.Foreach<int, string>(lineNumbers, delegate(int lineNumber, string sourceName)
                                {
                                    nasmTabList.SetErrorAt(sourceName, lineNumber);
                                });

                            }
                            else
                            {
                                if (dlg.LinkAfterCompilation)
                                {
                                    using (LinkerDialog lDlg = new LinkerDialog(currentSolution))
                                    {
                                        result = lDlg.ShowDialog();
                                        if (result == System.Windows.Forms.DialogResult.OK)
                                        {
                                            currentSolution.NameOfOutputBinary = lDlg.OutputName;
                                            saveAllToolStripMenuItem_Click(this, new EventArgs());
                                            outputWindow.AppendText("\n" + lDlg.LinkerOutput + "\n" + " Linking Completed On " + DateTime.Now.ToString());
                                            if (lDlg.LinkerOutput != "No Linker Output! Please check if a problem occured In The 'bin' Folder!" || !stringIsBlank(lDlg.LinkerOutput))
                                            {
                                                using (RunDialog rDlg = new RunDialog(currentSolution))
                                                {
                                                    result = rDlg.ShowDialog();
                                                    if (result == System.Windows.Forms.DialogResult.Cancel)
                                                    {
                                                        outputWindow.AppendText("\nUser Canceled Run...\n");
                                                    }
                                                    
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }

                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show("Something Went Clearly Wrong, The Application Will Close! The Monkeys Working Internally Did Leave Some Helpful Information In The Current Working Directory Of The Application; If It Cannot Be Found Please Contact Your Local Emergency Center!", "Error Monkeys Tried To Help But Couldn't Solve The Problem", MessageBoxButtons.OK, MessageBoxIcon.Error);
                ExceptionPrinter.Print(ex);
                this.Close();
            }
        }

        private void fixBrokenProjectToolToolStripMenuItem_Click(object sender, EventArgs e)
        {
            using (FixBrokenProjectDialog dlg = new FixBrokenProjectDialog())
            {
                dlg.ShowDialog();
            }
        }

        private void linkWithMiToolStripMenuItem_Click(object sender, EventArgs e)
        {
            try
            {
                using (LinkerDialog lDlg = new LinkerDialog(currentSolution))
                {
                    DialogResult result = lDlg.ShowDialog();
                    if (result == System.Windows.Forms.DialogResult.OK)
                    {
                        currentSolution.NameOfOutputBinary = lDlg.OutputName;
                        saveAllToolStripMenuItem_Click(this, new EventArgs());
                        outputWindow.AppendText("\n" + lDlg.LinkerOutput + "\n" + " Linking Completed On " + DateTime.Now.ToString());
                        if (lDlg.LinkerOutput != "No Linker Output! Please check if a problem occured In The 'bin' Folder!" || !stringIsBlank(lDlg.LinkerOutput))
                        {
                            using (RunDialog rDlg = new RunDialog(currentSolution))
                            {
                                result = rDlg.ShowDialog();
                                if (result == System.Windows.Forms.DialogResult.Cancel)
                                {
                                    outputWindow.AppendText("\nUser Canceled Run...\n");
                                }

                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show("Something Went Clearly Wrong, The Application Will Close! The Monkeys Working Internally Did Leave Some Helpful Information In The Current Working Directory Of The Application; If It Cannot Be Found Please Contact Your Local Emergency Center!", "Error Monkeys Tried To Help But Couldn't Solve The Problem", MessageBoxButtons.OK, MessageBoxIcon.Error);
                ExceptionPrinter.Print(ex);
                this.Close();
            }

        }

        private void buildUsingCustomScriptbatps1ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (currentSolution != null)
            {
                nasmTabList.ClearAllError();
                outputWindow.Clear();
                saveAllToolStripMenuItem_Click(this, new EventArgs());
                using (CustomScriptDialog dlg = new CustomScriptDialog(currentSolution))
                {
                    DialogResult result = dlg.ShowDialog();
                    if (result == System.Windows.Forms.DialogResult.OK)
                    {
                        outputWindow.Text = dlg.BuildOutput;
                        //if (!stringIsBlank(dlg.BuildOutput))
                        //{
                        //    ErrorLineNumbersExtracter extractor = new ErrorLineNumbersExtracter(dlg.BuildOutput);
                        //    Dictionary<int, string> lineNumbers = extractor.GetLineNumbers();
                        //    DictionaryHelper.Foreach<int, string>(lineNumbers, delegate(int lineNumber, string sourceName)
                        //    {
                        //        nasmTabList.SetErrorAt(sourceName, lineNumber);
                        //    });
                        //}
                    }
                    
                }
            }
            else
            {
                MessageBox.Show("A project must have been created or opened before accessing custom build script features!", "Access unavailable!",  MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
            }
        }

        private void setExecutionPolicyForPowershellToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ProcessStartInfo info = new ProcessStartInfo("powershell", "Set-ExecutionPolicy");
            info.Verb = "runas";
            Process.Start(info);
        }
    }
}
